home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1997 April: Mac OS SDK / Dev.CD Apr 97 SDK1.toast / Development Kits (Disc 1) / Apple Game Sprockets / RAVE SDK 1.06 GM for MacOS / Example Projects / GameScene / GSApp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-03-21  |  17.5 KB  |  583 lines  |  [TEXT/MPS ]

  1. // ===========================================================================
  2. //
  3. //     GSApp.c 
  4. //    
  5. //    Copyright (C) 1996 Apple Computer, Inc.  All rights reserved.
  6. //
  7. // ===========================================================================
  8.  
  9.  
  10. // ===========================================================================
  11. //    Includes
  12. // ===========================================================================
  13.  
  14. #include <stdlib.h>
  15.  
  16. #if (kQAPlatform == kQAMacOS)
  17.     #include <Memory.h>
  18.     #include <Windows.h>
  19.     #include <Displays.h>
  20.     #include <QuickDraw.h>
  21.     #include <string.h>
  22. #endif
  23.  
  24. #include "RAVE.h"
  25. #include "QD3DAcceleration.h"
  26.  
  27. #include "GSGameScene.h"
  28. #include "GSRandomTriMesh.h"
  29. #include "GSUtilities.h"
  30. #include "GSError.h"
  31.  
  32.  
  33. // ===========================================================================
  34. //    Constants
  35. // ===========================================================================
  36.  
  37. #define                        kWindowPercentage                0.75
  38. #define                        kMaxWindowNameLength            256
  39. #define                        kMaxEngineNameLength            256
  40. #define                        kMaxFormatNameLength            10
  41.  
  42.  
  43. // ===========================================================================
  44. //    Globals
  45. // ===========================================================================
  46.  
  47. #if (kQAPlatform == kQAMacOS)
  48. WindowPtr                    gWindowPtr = nil;
  49. #endif
  50.  
  51. char                        gEngineName[kMaxEngineNameLength] = 
  52.                                 "<Engine Name Too Long>";
  53. char                        gFormatNames[kQAPixel_CL8 + 1][kMaxFormatNameLength] = {
  54.                                 " : Alpha1",
  55.                                 " : RGB16",
  56.                                 " : ARGB16",
  57.                                 " : RGB32",
  58.                                 " : ARGB32",
  59.                                 " : CL4",
  60.                                 " : CL8" 
  61.                             };
  62.  
  63. TQADevice                    gDevice;
  64. TQARect                        gContentRect;
  65. TGSDrawInfo                    gDrawInfo;
  66. Boolean                        gUsingAppleHardware = false;
  67.  
  68.  
  69. // ===========================================================================
  70. //    Private Prototypes
  71. // ===========================================================================
  72.  
  73.     void 
  74. GSInitializeOperatingSystem(void);
  75.  
  76.     void 
  77. GSCleanUpAndQuit(void);
  78.  
  79.     TGSError
  80. GSCreateWindow(void);
  81.  
  82.     void
  83. GSClearWindow(void);
  84.  
  85.     void
  86. GSSetWindowName(
  87.     const char*                inWindowName);
  88.     
  89.     TGSError
  90. GSSetupDrawInfo(void);
  91.  
  92.     TGSError
  93. GSCreateDrawContext(
  94.     Boolean                    inUsingAppleHardware);
  95.  
  96.     void
  97. GSWaitForClick(void);
  98.  
  99.  
  100. // ===========================================================================
  101. //    main
  102. // ===========================================================================
  103.     int
  104. main(void)
  105. {
  106.     char                    windowName[kMaxWindowNameLength];
  107.     TGSError                gsError;
  108.     TQAImagePixelType        format;
  109.     
  110.         // this call enables Apple's QuickDraw3D Hardware Accelerator.  since
  111.         // this card is not a fully-compliant RAVE engine, it must be explicitly
  112.         // enabled by any app that wants to use it.  otherwise, it will never
  113.         // be returned by calls to QAGetFirstEngine().  the Apple HW Accelerator
  114.         // has a number of limitations which must be handled by any app that
  115.         // makes RAVE calls to it.  we handle these limitations by checking
  116.         // which engine is being used when setting up the TGSDrawInfo and when
  117.         // creating the draw context.
  118.     QAEngineEnable(kQAVendor_Apple, kQAEngine_AppleHW);
  119.     
  120.     GSInitializeOperatingSystem();
  121.     
  122.     gsError = GSCreateWindow();
  123.     
  124.     if (gsError != kGSError_None) {
  125.         GSCleanUpAndQuit();
  126.     }
  127.     
  128.     GSClearWindow();
  129.     
  130.     gsError = GSSetupDrawInfo();
  131.     
  132.     if (gsError != kGSError_None) {
  133.         GSCleanUpAndQuit();
  134.     }
  135.     
  136.     for (format = kQAPixel_RGB16; format <= kQAPixel_CL8; format++) {
  137.             // draw the textures and bitmaps in the same format
  138.         gDrawInfo.mTextureFormat = format;
  139.         gDrawInfo.mBitmapFormat = format;
  140.         
  141.             // copy the engine name into the window name string, and then append
  142.             // as much of the format name as will fit
  143.         strncpy(windowName, gEngineName, (kMaxWindowNameLength - 1));
  144.         strncat(windowName, gFormatNames[format], 
  145.                 (kMaxWindowNameLength - strlen(windowName) - 1));
  146.         
  147.             // set the window's name to the string we just created and then
  148.             // clear the window before we draw the next scene
  149.         GSSetWindowName(windowName);
  150.         GSClearWindow();
  151.         
  152.             // reset the random seed so that the random triangles will appear
  153.             // the same each time we call GSDrawGameScene
  154.         srand(1);
  155.         
  156.             // here's where the scene actually gets called
  157.         gsError = GSDrawGameScene(&gDrawInfo);
  158.     
  159.             // we now exit if we get any error other than one from RAVE.  a 
  160.             // RAVE error usually means an engine doesn't support a particular
  161.             // texture or bitmap format, so we can ignore it and go on to
  162.             // the next format.
  163.         if (gsError != kGSError_None && gsError != kGSError_RAVE) {
  164.             GSCleanUpAndQuit();
  165.         }
  166.         
  167.         GSWaitForClick();
  168.     }
  169.     
  170.         // now we draw the scene using the bitmap-only format kQAPixel_Alpha1
  171.     gDrawInfo.mTextureFormat = kQAPixel_RGB32;
  172.     gDrawInfo.mBitmapFormat = kQAPixel_Alpha1;
  173.     
  174.         // copy the engine name into the window name string, and then append
  175.         // as much of the format name as will fit
  176.     strncpy(windowName, gEngineName, (kMaxWindowNameLength - 1));
  177.     strncat(windowName, gFormatNames[kQAPixel_Alpha1], 
  178.             (kMaxWindowNameLength - strlen(windowName) - 1));
  179.     
  180.         // set the window's name to the string we just created and then
  181.         // clear the window before we draw the next scene
  182.     GSSetWindowName(windowName);
  183.     GSClearWindow();
  184.     
  185.     srand(1);
  186.     
  187.         // here's where the scene actually gets called
  188.     gsError = GSDrawGameScene(&gDrawInfo);
  189.  
  190.         // we now exit if we get any error other than one from RAVE.  a 
  191.         // RAVE error usually means an engine doesn't support a particular
  192.         // texture or bitmap format, so we can ignore it and go on to
  193.         // the next format.
  194.     if (gsError != kGSError_None && gsError != kGSError_RAVE) {
  195.         GSCleanUpAndQuit();
  196.     }
  197.     
  198.     GSWaitForClick();
  199.     
  200.     for (format = kQAPixel_RGB16; format <= kQAPixel_CL8; format++) {
  201.         gDrawInfo.mTextureFormat = format;
  202.         
  203.             // reset the random seed so that the random triangles will appear
  204.             // the same each time we call GSRandomTriMeshTexture
  205.         srand(1);
  206.         
  207.             // copy the engine name into the window name string, and then append
  208.             // as much of the format name as will fit
  209.         strncpy(windowName, gEngineName, (kMaxWindowNameLength - 1));
  210.         strncat(windowName, gFormatNames[format], 
  211.                 (kMaxWindowNameLength - strlen(windowName) - 1));
  212.         
  213.             // set the window's name to the string we just created and then
  214.             // clear the window before we draw the next scene
  215.         GSSetWindowName(windowName);
  216.         GSClearWindow();
  217.         
  218.             // here's where the scene actually gets called
  219.         gsError = GSRandomTriMeshTexture(&gDrawInfo);
  220.     
  221.             // we now exit if we get any error other than one from RAVE.  a 
  222.             // RAVE error usually means an engine doesn't support a particular
  223.             // texture or bitmap format, so we can ignore it and go on to
  224.             // the next format.
  225.         if (gsError != kGSError_None && gsError != kGSError_RAVE) {
  226.             GSCleanUpAndQuit();
  227.         }
  228.         
  229.         GSWaitForClick();
  230.     }
  231.     
  232.     GSCleanUpAndQuit();
  233. }
  234.  
  235.  
  236. // ===========================================================================
  237. //    GSInitializeOperatingSystem
  238. // ===========================================================================
  239.     void 
  240. GSInitializeOperatingSystem(void)
  241. {
  242. #if (kQAPlatform == kQAMacOS)
  243.     MaxApplZone();
  244.     
  245.     MoreMasters(); 
  246.     MoreMasters(); 
  247.     MoreMasters(); 
  248.     
  249.     InitGraf(&qd.thePort);
  250.     InitWindows();
  251.     InitCursor();
  252.  
  253.     FlushEvents(everyEvent, 0);
  254. #endif
  255. }
  256.  
  257.  
  258. // ===========================================================================
  259. //    GSCleanUpAndQuit
  260. // ===========================================================================
  261.     void 
  262. GSCleanUpAndQuit(void)
  263. {
  264.     if (gDrawInfo.mContext != nil) {
  265.             // now that we're finished rendering into the draw context, we 
  266.             // delete it, so the engine can free up that memory
  267.         QADrawContextDelete(gDrawInfo.mContext);
  268.     }
  269.     
  270. #if (kQAPlatform == kQAMacOS)
  271.     if (gWindowPtr != nil) {
  272.         DisposeWindow(gWindowPtr);
  273.     }
  274. #endif
  275.  
  276.     exit(0);
  277. }
  278.  
  279.  
  280. // ===========================================================================
  281. //    GSCreateWindow
  282. // ===========================================================================
  283.     TGSError
  284. GSCreateWindow(void)
  285. {
  286. #if (kQAPlatform == kQAMacOS)
  287.     GDHandle                deepestGDevice = nil;
  288.     Rect                    displayRect, windowRect;
  289.     long                    displayWidth, displayHeight, windowSideLength;
  290.  
  291.         // find the screen with the greatest number of colors
  292.     deepestGDevice = GSFindDeepestMacDisplay();
  293.     GSAssert_(deepestGDevice);
  294.     
  295.         // since this is Mac code, we use a GDevice as the RAVE device
  296.     gDevice.deviceType = kQADeviceGDevice;
  297.     gDevice.device.gDevice = deepestGDevice;
  298.     
  299.     displayRect = (**deepestGDevice).gdRect;
  300.     
  301.     displayWidth = displayRect.right - displayRect.left;
  302.     displayHeight = displayRect.bottom - displayRect.top;
  303.     
  304.         // size the window according to the size of the display
  305.     windowSideLength = (displayHeight < displayWidth) ? displayHeight : displayWidth;
  306.     windowSideLength = (long) (windowSideLength * kWindowPercentage);
  307.     
  308.     windowRect.left = displayRect.left + ((displayWidth - windowSideLength) / 2);
  309.     windowRect.top = displayRect.top + ((displayHeight - windowSideLength) / 2);
  310.     
  311.     windowRect.right = windowRect.left + windowSideLength;
  312.     windowRect.bottom = windowRect.top + windowSideLength;
  313.     
  314.         // the window rect is in global coordinates, but the TQARect which is 
  315.         // used to create a draw context must be in device-local coordinates,
  316.         // so calculate the window's position based on the upper-left corner 
  317.         // of the display it is on.
  318.     gDrawInfo.mContextRect.left = windowRect.left - displayRect.left;
  319.     gDrawInfo.mContextRect.right = windowRect.right - displayRect.left;
  320.     gDrawInfo.mContextRect.top = windowRect.top - displayRect.top;
  321.     gDrawInfo.mContextRect.bottom = windowRect.bottom - displayRect.top;
  322.  
  323.         // create a new color window, with no grow, zoom or close boxes
  324.     gWindowPtr = NewCWindow(nil, &windowRect, "\p", true, noGrowDocProc,
  325.             nil, false, nil);
  326.         
  327.     if (gWindowPtr == nil) {
  328.         return kGSError_OS;
  329.     }
  330. #endif
  331.     
  332.     return kGSError_None;
  333. }
  334.  
  335.  
  336. // ===========================================================================
  337. //    GSClearWindow
  338. // ===========================================================================
  339.     void
  340. GSClearWindow(void)
  341. {
  342. #if (kQAPlatform == kQAMacOS)
  343.     GrafPtr                    savedPort;
  344.     
  345.         // remember the current port
  346.     GetPort(&savedPort);
  347.     
  348.         // erase the content area of our window
  349.     SetPort(gWindowPtr);
  350.     EraseRect(&gWindowPtr->portRect);
  351.     
  352.         // reset the previous port
  353.     SetPort(savedPort);
  354. #endif
  355. }
  356.  
  357.  
  358. // ===========================================================================
  359. //    GSSetWindowName
  360. // ===========================================================================
  361.     void
  362. GSSetWindowName(
  363.     const char*                inWindowName)
  364. {
  365. #if (kQAPlatform == kQAMacOS)
  366.     Str255                    pascalWindowName;
  367.     short                    windowNameLength = 0;
  368.     
  369.     windowNameLength = strlen(inWindowName);
  370.     
  371.         // convert the incoming C string to a Pascal string
  372.     BlockMoveData(inWindowName, &pascalWindowName[1], windowNameLength);
  373.  
  374.         // set the length of the Pascal string 
  375.     pascalWindowName[0] = windowNameLength;
  376.     
  377.         // set the window's title
  378.     SetWTitle(gWindowPtr, pascalWindowName);
  379. #endif
  380. }
  381.  
  382.  
  383. // ===========================================================================
  384. //    GSSetupDrawInfo
  385. // ===========================================================================
  386.     TGSError
  387. GSSetupDrawInfo(void)
  388. {
  389.     long                    vendorID = 0, engineID = 0, engineNameLength = 0;
  390.     Boolean                    usingAppleHardware = false;
  391.     TGSError                gsError;
  392.     TQAError                qaError;
  393.     
  394.         // find the first engine which is best suited to the device we'll be
  395.         // drawing on
  396.     gDrawInfo.mEngine = QADeviceGetFirstEngine(&gDevice);
  397.     
  398.     if (gDrawInfo.mEngine == nil) {
  399.         return kGSError_RAVE;
  400.     }
  401.  
  402.         // get the length of the engine's name
  403.     qaError = QAEngineGestalt(gDrawInfo.mEngine, kQAGestalt_ASCIINameLength, &engineNameLength);
  404.     
  405.     if (qaError != kQANoErr) {
  406.         return kGSError_RAVE;
  407.     }
  408.     
  409.     if (engineNameLength < kMaxEngineNameLength) {
  410.             // the engine's name will fit into our buffer, so get it
  411.         qaError = QAEngineGestalt(gDrawInfo.mEngine, kQAGestalt_ASCIIName, &gEngineName);
  412.         
  413.         if (qaError != kQANoErr) {
  414.             return kGSError_RAVE;
  415.         }
  416.     }
  417.     
  418.         // use the TQADevice we set up in GSCreateWindow
  419.     gDrawInfo.mDevice = gDevice;
  420.     
  421.         // you can change the format of the textures by uncommenting a different
  422.         // line below.  note that if you choose CL4 or CL8, you must set 
  423.         // mTextureMakeMipMap to false, because the GSPicture object cannot
  424.         // currently mipmap color-lookup table textures.  also, GSPicture does 
  425.         // not do a good job converting 32-bit PICTs with alpha channels 
  426.         // into CL4 or CL8 textures.
  427. //    gDrawInfo.mTextureFormat = kQAPixel_RGB16;
  428. //    gDrawInfo.mTextureFormat = kQAPixel_ARGB16;
  429. //    gDrawInfo.mTextureFormat = kQAPixel_RGB32;
  430. //    gDrawInfo.mTextureFormat = kQAPixel_ARGB32;
  431. //    gDrawInfo.mTextureFormat = kQAPixel_CL4;
  432.     gDrawInfo.mTextureFormat = kQAPixel_CL8;
  433.     
  434.         // the textures will not be locked or mipmapped
  435.     gDrawInfo.mTextureFlags = kQATexture_None;
  436.     
  437.         // we do not want them to be detached or mipmapped
  438.     gDrawInfo.mTextureDetach = false;
  439.     gDrawInfo.mTextureMakeMipMap = false;
  440.  
  441.     gDrawInfo.mTextureMakeBlackTransparent = true;
  442.     gDrawInfo.mTextureUseTransparentIndex = false;
  443.     
  444.         // you can change the format of the bitmaps by uncommenting a different
  445.         // line below.  note that if you use RGB16 or RGB32, the transparent
  446.         // areas of the bitmaps will be opaque, since RAVE ignores the alpha
  447.         // values in those two modes.  also, GSPicture does not do a good job
  448.         // converting 32-bit PICTs with alpha channels into CL4 or CL8 bitmaps.
  449. //    gDrawInfo.mBitmapFormat = kQAPixel_Alpha1;
  450. //    gDrawInfo.mBitmapFormat = kQAPixel_RGB16;
  451. //    gDrawInfo.mBitmapFormat = kQAPixel_ARGB16;
  452. //    gDrawInfo.mBitmapFormat = kQAPixel_RGB32;
  453. //    gDrawInfo.mBitmapFormat = kQAPixel_ARGB32;
  454. //    gDrawInfo.mBitmapFormat = kQAPixel_CL4;
  455.     gDrawInfo.mBitmapFormat = kQAPixel_CL8;
  456.  
  457.         // the bitmaps will not be locked or detached
  458.     gDrawInfo.mBitmapFlags = kQABitmap_None;
  459.     gDrawInfo.mBitmapDetach = false;
  460.     
  461.         // we want the black background of the bitmaps to be transparent if
  462.         // we're using one of the ARGB formats, and we want the first color in
  463.         // the color table to be transparent if we're using a CL format.
  464.     gDrawInfo.mBitmapMakeBlackTransparent = true;
  465.     gDrawInfo.mBitmapUseTransparentIndex = true;
  466.     
  467.     
  468.     qaError = QAEngineGestalt(gDrawInfo.mEngine, kQAGestalt_EngineID, &engineID);
  469.     
  470.     if (qaError != kQANoErr) {
  471.         return kGSError_RAVE;
  472.     }
  473.     
  474.         // we're only interested in special-casing Apple's first hardware card
  475.     gUsingAppleHardware = (vendorID == kQAVendor_Apple && engineID == kQAEngine_AppleHW);
  476.     
  477.     if (gUsingAppleHardware) {
  478.             // we are using the Apple Hardware Accelerator, which is not a
  479.             // RAVE-compliant engine.  therefore we have to change a few things
  480.             // to handle its idiosyncracies.
  481.             //
  482.             // the Apple HW Accelerator requires that all textures submitted to 
  483.             // it be mipmapped.  if you want the textures to be in kQAPixel_CL8 
  484.             // or kQAPixel_CL4 format, then you must set this field to false, 
  485.             // since the TGSImage object currently cannot mipmap textures in 
  486.             // color table format.  this means you cannot use color table 
  487.             // textures with the Apple HW Accelerator (which currently cannot 
  488.             // handle them anyway).
  489.         gDrawInfo.mTextureMakeMipMap = true;
  490.         
  491.             // the previous line will cause the TGSImage object to be mipmapped.
  492.             // the next line contains the flags which are passed to QATextureNew
  493.             // so that the call will know the textures have been mipmapped.
  494.         gDrawInfo.mTextureFlags |= kQATexture_Mipmap;
  495.         
  496.             // the Apple HW also requires that all textures be in RGB32 format
  497.         gDrawInfo.mTextureFormat = kQAPixel_RGB32;
  498.         
  499.             // the only bitmap format that the Apple HW can handle is Alpha1
  500.         gDrawInfo.mBitmapFormat = kQAPixel_Alpha1;
  501.     }
  502.     
  503.     gsError = GSCreateDrawContext(gUsingAppleHardware);
  504.     
  505.     if (gsError != kGSError_None) {
  506.         return gsError;
  507.     }
  508.     
  509.     return kGSError_None;
  510. }
  511.  
  512.  
  513. // ===========================================================================
  514. //    GSCreateDrawContext
  515. // ===========================================================================
  516.     TGSError
  517. GSCreateDrawContext(
  518.     Boolean                    inUsingAppleHardware)
  519. {
  520.     TQAError                qaError;
  521.     
  522.     gDrawInfo.mContextFlags = kQAContext_None;
  523.     
  524.         // you can make the draw context be double-buffered by uncommenting the
  525.         // following line.  when a context is double-buffered, you won't see
  526.         // anything until the entire scene is drawn, at which point everything
  527.         // will appear.
  528. //    gDrawInfo.mContextFlags |= kQAContext_DoubleBuffer;
  529.     
  530.     if (inUsingAppleHardware) {
  531.             // Apple's HW Accelerator requires all draw contexts to have the 
  532.             // kQAContext_DeepZ flag set
  533.         gDrawInfo.mContextFlags |= kQAContext_DeepZ;
  534.     }
  535.     
  536.     qaError = QADrawContextNew(&gDrawInfo.mDevice, &gDrawInfo.mContextRect, nil,
  537.             gDrawInfo.mEngine, gDrawInfo.mContextFlags, &gDrawInfo.mContext);
  538.             
  539.     if (qaError != kQANoErr) {
  540.         return kGSError_RAVE;
  541.     }
  542.     
  543.         // once you've created the draw context, there are a number of state
  544.         // variables which can be set, such as the background color, turning
  545.         // antialiasing on and off, etc.  below we set some of these if we
  546.         // are using the Apple HW Accelerator.
  547.     if (inUsingAppleHardware) {
  548.             // we turn on the Perspective Z flag so that Apple's HW will
  549.             // perspective-correct the textures.  the Apple Software drawing 
  550.             // engine always does perspective-correction.
  551.         QASetInt(gDrawInfo.mContext, kQATag_PerspectiveZ, kQAPerspectiveZ_On);
  552.         
  553.             // Apple's HW also requires the optional texture mapping operation
  554.             // state variable to be set a certain way
  555.         QASetInt(gDrawInfo.mContext, kQATag_TextureOp, 
  556.                 kQATextureOp_Modulate & kQATextureOp_Highlight);
  557.     }
  558.     
  559.     return kGSError_None;
  560. }
  561.  
  562.  
  563. // ===========================================================================
  564. //    GSWaitForClick
  565. // ===========================================================================
  566.     void
  567. GSWaitForClick(void)
  568. {
  569. #if (kQAPlatform == kQAMacOS)
  570.     EventRecord                theEvent;
  571.     
  572.     while (!Button())
  573.         GetNextEvent(everyEvent, &theEvent);
  574.     
  575.     while(Button())
  576.         ;
  577.         
  578.     FlushEvents(everyEvent, 0);
  579. #endif
  580. }
  581.  
  582.  
  583.